View Javadoc
1   package org.apache.maven.surefire.junitcore;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Collection;
23  import java.util.List;
24  import java.util.concurrent.ConcurrentLinkedQueue;
25  import java.util.concurrent.atomic.AtomicBoolean;
26  import java.util.concurrent.atomic.AtomicInteger;
27  
28  import org.apache.maven.surefire.report.ReportEntry;
29  import org.apache.maven.surefire.report.RunListener;
30  import org.apache.maven.surefire.report.SimpleReportEntry;
31  
32  import org.junit.runner.Description;
33  
34  /**
35   * * Represents the test-state of a testset that is run.
36   */
37  public class TestSet
38  {
39      private static final InheritableThreadLocal<TestSet> TEST_SET = new InheritableThreadLocal<TestSet>();
40  
41      private final Description testSetDescription;
42  
43      private final Collection<TestMethod> testMethods = new ConcurrentLinkedQueue<TestMethod>();
44  
45      private final AtomicBoolean played = new AtomicBoolean();
46  
47      private final AtomicInteger numberOfCompletedChildren = new AtomicInteger();
48  
49      // While the two parameters may seem duplicated, it is not entirely the case,
50      // since numberOfTests has the correct value from the start, while testMethods grows as method execution starts.
51  
52      private final AtomicInteger numberOfTests = new AtomicInteger();
53  
54      private volatile boolean allScheduled;
55  
56      public TestSet( Description testSetDescription )
57      {
58          this.testSetDescription = testSetDescription;
59      }
60  
61      public void replay( RunListener target )
62      {
63          if ( played.compareAndSet( false, true ) )
64          {
65              try
66              {
67                  ReportEntry report = createReportEntry( null );
68  
69                  target.testSetStarting( report );
70  
71                  long startTile = 0;
72                  long endTime = 0;
73                  for ( TestMethod testMethod : testMethods )
74                  {
75                      if ( startTile == 0 || testMethod.getStartTime() < startTile )
76                      {
77                          startTile = testMethod.getStartTime();
78                      }
79  
80                      if ( endTime == 0 || testMethod.getEndTime() > endTime )
81                      {
82                          endTime = testMethod.getEndTime();
83                      }
84  
85                      testMethod.replay( target );
86                  }
87  
88                  int elapsed = (int) ( endTime - startTile );
89  
90                  report = createReportEntry( elapsed );
91  
92                  target.testSetCompleted( report );
93              }
94              catch ( Exception e )
95              {
96                  throw new RuntimeException( e );
97              }
98          }
99      }
100 
101     public TestMethod createThreadAttachedTestMethod( ReportEntry description )
102     {
103         TestMethod testMethod = new TestMethod( description, this );
104         addTestMethod( testMethod );
105         testMethod.attachToThread();
106         return testMethod;
107     }
108 
109     private ReportEntry createReportEntry( Integer elapsed )
110     {
111         final String className = testSetDescription.getClassName();
112         final boolean isJunit3 = className == null;
113         final String classNameToUse;
114         if ( isJunit3 )
115         {
116             List<Description> children = testSetDescription.getChildren();
117             classNameToUse = children.isEmpty() ? testSetDescription.toString() : children.get( 0 ).getClassName();
118         }
119         else
120         {
121             classNameToUse = className;
122         }
123         return new SimpleReportEntry( classNameToUse, classNameToUse, elapsed );
124     }
125 
126     public void incrementTestMethodCount()
127     {
128         numberOfTests.incrementAndGet();
129     }
130 
131     private void addTestMethod( TestMethod testMethod )
132     {
133         testMethods.add( testMethod );
134     }
135 
136     public void incrementFinishedTests( RunListener reporterManager, boolean reportImmediately )
137     {
138         numberOfCompletedChildren.incrementAndGet();
139         if ( allScheduled && isAllTestsDone() && reportImmediately )
140         {
141             replay( reporterManager );
142         }
143     }
144 
145     public void setAllScheduled( RunListener reporterManager )
146     {
147         allScheduled = true;
148         if ( isAllTestsDone() )
149         {
150             replay( reporterManager );
151         }
152     }
153 
154     private boolean isAllTestsDone()
155     {
156         return numberOfTests.get() == numberOfCompletedChildren.get();
157     }
158 
159     public void attachToThread()
160     {
161         TEST_SET.set( this );
162     }
163 
164     public static TestSet getThreadTestSet()
165     {
166         return TEST_SET.get();
167     }
168 }